package com.zy.explore.license.interfaces.facade.v1;

import com.alibaba.fastjson.JSON;
import com.zy.explore.license.infrastructure.config.LicenseConfig;
import com.zy.explore.license.infrastructure.constant.ProjectConstant;
import com.zy.explore.license.infrastructure.exception.MessageCode;
import com.zy.explore.license.infrastructure.license.AbstractServerInfos;
import com.zy.explore.license.infrastructure.license.LicenseCheckModel;
import com.zy.explore.license.infrastructure.license.LicenseCreator;
import com.zy.explore.license.infrastructure.license.LicenseCreatorParam;
import com.zy.explore.license.infrastructure.license.LinuxServerInfos;
import com.zy.explore.license.infrastructure.license.WindowsServerInfos;
import com.zy.explore.license.infrastructure.util.CommandLineUtil;
import com.zy.explore.license.infrastructure.util.DateUtil;
import com.zy.explore.license.infrastructure.util.ZipUtil;
import com.zy.explore.license.interfaces.frm.CustomerLicenseInfoSaveFrm;
import com.zy.explore.license.interfaces.vo.ResultVO;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.Date;

/**
 * 用于生成证书文件，不能放在给客户部署的代码里
 *
 * @author zifangsky
 * @date 2018/4/26
 * @since 1.0.0
 */
@Slf4j
@Api(tags = "证书API")
@RestController
@RequestMapping("/v1/license")
public class LicenseCreatorFacade {

    @Value("${license.clear.zip:true}")
    private Boolean clearZip;

    @Value("${license.clear.dir:true}")
    private Boolean clearDir;

    /**
     * 属性说明：许可证配置，必须引入
     *
     * @see LicenseConfig
     */
    @Resource
    private LicenseConfig licenseConfig;

    /**
     * 获取服务器硬件信息
     *
     * @param osName 操作系统类型，如果为空则自动判断
     * @return com.zy.explore.license.infrastructure.license.LicenseCheckModel
     * @author zifangsky
     * @date 2018/4/26 13:13
     * @since 1.0.0
     */
    @ApiOperationSupport(order = 10, author = "🇨🇳中国印🇨🇳")
    @ApiOperation("①获取服务器信息")
    @GetMapping(value = "/getServerInfos", produces = {MediaType.APPLICATION_JSON_VALUE})
    public LicenseCheckModel getServerInfos(@RequestParam(value = "osName", required = false) String osName) {
        //操作系统类型
        if (StringUtils.isBlank(osName)) {
            osName = System.getProperty(ProjectConstant.OS_NAME);
        }
        osName = osName.toLowerCase();

        AbstractServerInfos abstractServerInfos;

        //根据不同操作系统类型选择不同的数据获取方法
        if (osName.startsWith("windows")) {
            abstractServerInfos = new WindowsServerInfos();
        } else if (osName.startsWith("linux")) {
            abstractServerInfos = new LinuxServerInfos();
        } else {//其他服务器类型
            abstractServerInfos = new LinuxServerInfos();
        }
        return abstractServerInfos.getServerInfos();
    }

    /**
     * 生成证书
     *
     * @param param 生成证书需要的参数，如：{"subject":"ccx-models","privateAlias":"privateKey","keyPass":"5T7Zz5Y0dJFcqTxvzkH5LDGJJSGMzQ","storePass":"3538cef8e7","licensePath":"C:/Users/zifangsky/Desktop/license.lic","privateKeysStorePath":"C:/Users/zifangsky/Desktop/privateKeys.keystore","issuedTime":"2018-04-26 14:48:12","expiryTime":"2018-12-31 00:00:00","consumerType":"User","consumerAmount":1,"description":"这是证书描述信息","licenseCheckModel":{"ipAddress":["192.168.245.1","10.0.5.22"],"macAddress":["00-50-56-C0-00-01","50-7B-9D-F9-18-41"],"cpuSerial":"BFEBFBFF000406E3","mainBoardSerial":"L1HF65E00X9"}}
     * @return java.util.Map<java.lang.String, java.lang.Object>
     * @author zifangsky
     * @date 2018/4/26 13:13
     * @since 1.0.0
     */
    @ApiOperationSupport(order = 20, author = "🇨🇳中国印🇨🇳")
    @ApiOperation("②生成license")
    @PostMapping(value = "/generateLicense", produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResultVO<?> generateLicense(@RequestBody LicenseCreatorParam param) {
        // 设置默认值
        param.setPrivateAlias(LicenseConfig.privateAlias);
        param.setKeyPass(LicenseConfig.privateStorePass);
        param.setPublicStorePass(LicenseConfig.publicStorePass);
        param.setPrivateKeysStorePath(LicenseConfig.licensePath + File.separator + LicenseConfig.PRI_KEY_STORE_NAME);
        if (StringUtils.isBlank(param.getLicensePath())) {
            param.setLicensePath(LicenseConfig.licensePath);
        }
        if (StringUtils.isBlank(param.getSubject())) {
            param.setSubject(LicenseConfig.subject);
        }
        if (param.getIssuedTime() == null) {
            param.setIssuedTime(new Date());
        }
        if (param.getExpiryTime() == null) {
            param.setExpiryTime(DateUtil.getFutureDate(30));
        } else {
            if (param.getExpiryTime().getTime() < System.currentTimeMillis() || param.getExpiryTime().getTime() < param.getIssuedTime().getTime()) {
                throw MessageCode.EXPIRY_TIME_ERROR.toException();
            }
        }
        LicenseCreator licenseCreator = new LicenseCreator(param);
        boolean result = licenseCreator.generateLicense(param.getSubject() + File.separator + LicenseConfig.LICENSE_NAME);
        if (result) {
            String publicKeyStoreFile = LicenseConfig.licensePath + File.separator + LicenseConfig.PUB_KEY_STORE_NAME;
            // 将公钥拷贝至生成的证书的目录下
            // windows下：copy D:\license\publicCerts.keystore D:\license\customerName
            // linux下： cp /license/publicCerts.keystore /license/customerName
            String cmd = "copy " + publicKeyStoreFile + " " + LicenseConfig.licensePath + File.separator + param.getSubject();
            if (System.getProperty(ProjectConstant.OS_NAME).toLowerCase().startsWith(ProjectConstant.WINDOWS_PREFIX)) {
                CommandLineUtil.executeWindowsCmd(cmd);
            } else {
                cmd = "cp " + publicKeyStoreFile + " " + LicenseConfig.licensePath + File.separator + param.getSubject();
                CommandLineUtil.executeLinuxCmd(cmd);
            }
            return ResultVO.getSuccess(param);
        }
        return ResultVO.getError("证书生成失败");
    }

    @ApiOperationSupport(order = 30, author = "🇨🇳中国印🇨🇳")
    @ApiOperation("③生成license下载")
    @PostMapping(value = "/downloadLicense", produces = {MediaType.APPLICATION_JSON_VALUE})
    public void genLicense(@RequestBody @Validated CustomerLicenseInfoSaveFrm frm, HttpServletResponse response) throws Exception {
        // 设置默认值
        LicenseCreatorParam param = LicenseCreatorParam.builder()
                // 直接使用配置的证书主体名称
                .subject(LicenseConfig.subject)
                .customerType(LicenseConfig.customerType)
                .privateAlias(LicenseConfig.privateAlias)
                .keyPass(LicenseConfig.privateStorePass)
                .publicStorePass(LicenseConfig.publicStorePass)
                .privateKeysStorePath(LicenseConfig.licensePath + File.separator + LicenseConfig.PRI_KEY_STORE_NAME)
                .licensePath(LicenseConfig.licensePath)
                .consumerAmount(1)

                .issuedTime(frm.getIssueTime())
                .expiryTime(frm.getExpiryTime())
                .licenseCheckModel(JSON.parseObject(frm.getLicenseCheckModel(), LicenseCheckModel.class))
                .description("证书管理后台生成的证书")
                .build();
        LicenseCreator licenseCreator = new LicenseCreator(param);
        boolean result = licenseCreator.generateLicense(frm.getCustomerName() + File.separator + LicenseConfig.LICENSE_NAME);
        // 生成成功
        if (result) {
            // 压缩文件为zip
            String licenseFile = LicenseConfig.licensePath + File.separator + frm.getCustomerName();
            String publicKeyStoreFile = LicenseConfig.licensePath + File.separator +  LicenseConfig.PUB_KEY_STORE_NAME;
            // 将公钥拷贝至生成的证书的目录下
            // windows下：copy D:\license\publicCerts.keystore D:\license\customerName
            // linux下： cp /license/publicCerts.keystore /license/customerName
            String cmd = "copy " + publicKeyStoreFile + " " + LicenseConfig.licensePath + File.separator + frm.getCustomerName();
            if (System.getProperty(ProjectConstant.OS_NAME).toLowerCase().startsWith(ProjectConstant.WINDOWS_PREFIX)) {
                CommandLineUtil.executeWindowsCmd(cmd);
            } else {
                cmd = "cp " + publicKeyStoreFile + " " + LicenseConfig.licensePath + File.separator + frm.getCustomerName();
                CommandLineUtil.executeLinuxCmd(cmd);
            }

            String outputFileName = frm.getCustomerName() + "-license.zip";

            byte[] data = ZipUtil.getOutputBytes(response, licenseFile, outputFileName, outputFileName, clearZip, clearDir);
            IOUtils.write(data, response.getOutputStream());
        }
        throw MessageCode.SYSTEM_BUSY.toException();
    }


}
